#include"CentralCache.h"
#include"PageCache.h"
 CentralCache::CentralCache(){}
 CentralCache  CentralCache::_sInst;
 size_t  CentralCache::FetchRangeObj(void*&start,void*&end,size_t n,size_t size){
    size_t index=Sizeclass::Index(size);
    _spanLists[index]._mtx.lock();
    Span* span=GetoneSpan(_spanLists[index],size);
    assert(span);
    assert(span->_freelist);
    start=span->_freelist;
    end=start;
    size_t actualNum=1;
    int i=0;
    while(i<n-1&&NextObj(end)){
        end=NextObj(end);
        i++;
        actualNum++;
    }
    span->_freelist=NextObj(end);
    NextObj(end)=nullptr;
    _spanLists[index]._mtx.unlock();
    span->_usecount+=actualNum;
    return actualNum;
 }
 Span* CentralCache::GetoneSpan(SpanList&list,size_t byte_size){
       //查看当前的spanlist 是否含有未分配的对象span
       Span*it=list.Begin();
       while(it!=list.End()){
            if(it->_freelist!=nullptr){
                return it;
            }
            else it=it->_next;
       }
       //走到这里说明没有空闲的span了，只能找pagecache分配
       //走到这里之后，释放锁，以便后续线程去归还内存不会阻塞
       //不会影响后续内存分配，因为没有内存，后续线程也会向后面PageCache申请内存
    list._mtx.unlock();
    PageCache::Instance()->_pagemtx.lock();
    Span*span=PageCache::Instance()->newpage(Sizeclass::NumMovePage(byte_size));
    span->_isUse=true;
    span->_objsize=byte_size;
    PageCache::Instance()->_pagemtx.unlock();
    //切好span后并挂好,不需要加锁，因为其他线程拿不到这块span
    char*start=(char*)(span->_pageID<<PAGE_SHIFT);
    size_t bytes=span->_n<<PAGE_SHIFT;
    //先切一块下来,方便尾插
    char*end=start+bytes;
    span->_freelist=start;
    start+=byte_size;
    void *tail=span->_freelist;
    while(start<end){
        NextObj(tail)=start;
        tail=NextObj(tail);
        start+=byte_size;
    }
    NextObj(tail)=nullptr;
    
    //切好后挂到桶里面需要加锁
    NextObj(tail)=nullptr;
    list._mtx.lock();
    list.PushFront(span);
    list._mtx.unlock();
    return span;
 }
 void CentralCache::ReleaseListSpans(void*start,size_t byte_size){
     size_t index=Sizeclass::Index(byte_size);
     _spanLists[index]._mtx.lock();
     while(start){
        void* next=NextObj(start);
        Span*span=PageCache::Instance()->MapObjectTospan(start);
        NextObj(start)=span->_freelist;
        span->_freelist=start;
        span->_usecount--;
        start=next;
        //如果span的使用计数为0，说明这个span没有被使用，可以释放掉
        if(span->_usecount==0){
           _spanLists[index].Erase(span);
           span->_freelist=nullptr;
           span->_next=nullptr;
           span->_prev=nullptr;
           //释放span给pageCahe时，使用pageCahe的锁就可以了
           //暂时解开锁，以便后续线程归还内存不会阻塞
           _spanLists[index]._mtx.unlock();
           PageCache::Instance()->_pagemtx.lock();
           PageCache::Instance()->ReleaseToPageCache(span);
           PageCache::Instance()->_pagemtx.unlock();
           _spanLists[index]._mtx.lock();
        }
     }
     _spanLists[index]._mtx.unlock();
 }
 